package roborally.program.command;

import java.util.List;

import roborally.itemsonboard.Robot;
import roborally.program.text.TextManipulation;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Immutable;
import be.kuleuven.cs.som.annotate.Raw;

/**
 * A class representing a while-statement.
 * This consists of a condition and a body.
 * The body is executed as long as the condition is true.
 * 
 * @author Molderez Tom, 2de bach Ingenieurswetenschappen Computerwetenschappen-Elektrotechniek and Reniers Jorn, 2de bach Ingenieurswetenschappen Werktuigkunde-Computerwetenschappen
 * @version 1.2
 *
 */
public class WhileCommand extends ConditionalCommand {

	/**
	 * Creates a new WhileCommand.
	 * 
	 * @param condition The condition of this whileCommand.
	 * @param commands The interal commands of this whileCommand.
	 * @post The condition of this will be equal to the given condition.
	 * @post For every command in commands, according the order, this new will contain the specific command.
	 * @throws IllegalArgumentException
	 * 		When the commands are not valid according isValidInternalCommands.
	 * 		| !isValidInternalCommands(commands)
	 * @throws IllegalArgumentException
	 * 		When the condition is not valid, specified by isValidCondition.
	 * 		| !isValidCondition(condition)
	 */
	public WhileCommand(Condition condition, List<? extends Command> commands) {
		super(condition, commands);
	}

	/**
	 * Executes this WhileCommand by executing all the interal commands until the condition
	 * evaluates to false if the given
	 * robot is valid.
	 * 
	 * @param robot The robot that must be manipulated.
	 * @effect As long as the condition of this while command returns true after evaluating,
	 * all the commands in getInteralCommands() will be executed, in the specified order. 
	 */
	@Override
	public void execute(Robot robot) throws IllegalArgumentException {
		do {
			this.getCondition().execute(robot);
			if(this.getCondition().getReturnValue())
				super.execute(robot);
		} while(this.getCondition().getReturnValue());
	}
	
	/**
	 * Search for and executes the (minimumSteps + 1) th basic command (execution command)
	 * The currentSteps is a counter that counts how many basic commands we already passed.
	 * When currentStep is equal to minimumSteps, that basic command will be executed.
	 * 
	 * @param minimumSteps The amount of basic commands we already have executed. 
	 * @param currentSteps The amount of basic commands we already passed.
	 * @param robot The robot that will be manipulated by the given program.
	 * @effect As long as the condition of this while command returns true after evaluating, 
	 * for each interalCommand, we will invoke the next method again. But when 
	 * currentSteps become greater then minimumSteps, no more must happen and the method
	 * jumps out of the loop.
	 * @return The new currentSteps which will increase when a basic command is found.
	 * @throws IllegalArgumentException
	 * 		When the robot is not valid.
	 * @note The return value is not always equal to the amount of basic commands of this command
	 * added by the start value of it. This is only the case if the result is smaller then
	 * minimumSteps. Otherwise it doesn't care because the stop condition of the recursive
	 * structure of the methods is satisfied.
	 */
	@Override
	public int next(int minimumSteps, int currentSteps, Robot robot) throws IllegalArgumentException {
		do {
			this.getCondition().execute(robot);
			if(this.getCondition().getReturnValue()) {
				currentSteps = super.next(minimumSteps, currentSteps, robot);
			}
		} while(this.getCondition().getReturnValue() && currentSteps <= minimumSteps);
		return currentSteps;
	}

	/**
	 * Returns a String representation of this WhileCommand.
	 * 
	 * @param leftSpaces The amount of left spaces this while command must
	 * be added to each new line.
	 * @return A String containing this while commant with the condition on one line,
	 * each interal on a new line and separated by the required brackets where needed.
	 */
	@Override
	public String write(String leftSpaces) {
		String write = new String();
		write = leftSpaces + "(" + WHILE; 
		write = write + " " + this.getCondition().write("") + "\n";
		write = write + super.write(leftSpaces + TextManipulation.LEFT_SPACE);
		write = write + leftSpaces + ")\n";
		
		return write;
	}
	
	/**
	 * Returns the textual source code of this type of command.
	 */
	@Immutable @Basic @Raw
	public static final String getWord() {
		return WHILE;
	}
	
	/**
	 * The source code word of the WhileCommand.
	 */
	private static final String WHILE  = "while";
}
